﻿// -----------------------------------------------------------------------
// <copyright file="SqlServerInstaller.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

namespace Centido.Core
{
    using System;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Properties;

    /// <summary>
    ///   Sql server metadata installer
    /// </summary>
    public sealed class SqlServerInstaller : Installer
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Centido.Core.SqlServerInstaller"/> class.
        /// </summary>
        public SqlServerInstaller()
        {
            
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="Centido.Core.SqlServerInstaller"/> class.
        /// </summary>
        /// <param name="dbConnectionString">The database connection string.</param>
        /// <param name="dbProviderName">The database provider invariant name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="dbConnectionString"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="dbProviderName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="dbConnectionString"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="dbProviderName"/> is an empty string.</exception>        
        public SqlServerInstaller(string dbConnectionString, string dbProviderName)
            : base(dbConnectionString, dbProviderName)
        {
        }

        /// <summary>
        ///   Gets the database product name.
        /// </summary>
        public override string ProductName
        {
            get { return "SQLSERVER"; }
        }

        /// <summary>
        ///   Gets the version of the metadata schema.
        /// </summary>
        public override int SchemaVersion
        {
            get { return 3; }
        }

        /// <summary>
        ///   Gets the version of the metadata logic.
        /// </summary>
        public override int LogicVersion
        {
            get { return 6; }
        }

        /// <summary>
        ///   Installs the metadata schema.
        /// </summary>
        /// <returns>Returns the current installer.</returns>
        public override Installer InstallSchema()
        {
            ExecuteScript(Resources.Installation_schema_sqlserver);

            return this;
        }

        /// <summary>
        ///   Installs the metadata logic.
        /// </summary>
        /// <returns>Returns the current installer.</returns>
        public override Installer InstallLogic()
        {
            ExecuteScript(Resources.Installation_logic_sqlserver);

            return this;
        }

        /// <summary>
        ///   Creates an application user.
        /// </summary>
        /// <param name = "userName">The application user name.</param>
        /// <param name="userPassword">The application user password.</param>
        /// <param name="dbName">The application user database name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="userName"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="userPassword"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="dbName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="userName"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="userPassword"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="dbName"/> is an empty string.</exception>
        /// <returns>Returns the current installer.</returns>
        public override Installer CreateAppUser(string userName, string userPassword, string dbName)
        {
            if (userName == null)
                throw new ArgumentNullException("userName");
            if (userPassword == null)
                throw new ArgumentNullException("userPassword");
            if (dbName == null)
                throw new ArgumentNullException("dbName");
            if (userName.Trim().Length == 0)
                throw new ArgumentException("The application user name cannot be empty.");
            if (userPassword.Trim().Length == 0)
                throw new ArgumentException("The application user password cannot be empty.");
            if (dbName.Trim().Length == 0)
                throw new ArgumentException("The application database name cannot be empty.");

            userName = userName.Trim();
            dbName = dbName.Trim();

            DbRule.TestIdentifier(userName);
            DbRule.TestIdentifier(dbName);

            ExecuteScript(GetAppUserInstallationScript(userName, userPassword, dbName));

            return this;
        }


        /// <summary>
        ///   Retrieves the application user installation script.
        /// </summary>
        /// <param name="userName">The application user name.</param>
        /// <param name="userPassword">The application user password.</param>
        /// <param name="dbName">The application user database name.</param>
        /// <returns>Returns the application user installation script.</returns>
        public override string GetAppUserInstallationScript(string userName, string userPassword, string dbName)
        {
            if (userName == null)
                throw new ArgumentNullException("userName");
            if (userPassword == null)
                throw new ArgumentNullException("userPassword");
            if (dbName == null)
                throw new ArgumentNullException("dbName");

            userName = userName.Trim();
            dbName = dbName.Trim();

            var script = Resources.Installation_meta_owner_sqlserver;

            if (!string.IsNullOrEmpty(userName))
                script = script.Replace(@"@@user_name@@", userName);
            
            if (!string.IsNullOrEmpty(userPassword))
                script = script.Replace(@"@@user_password@@", userPassword);

            if (!string.IsNullOrEmpty(dbName))
                script = script.Replace(@"@@db_name@@", dbName);

            return script;
        }


        /// <summary>
        ///   Uninstalls the metadata.
        /// </summary>
        public override Installer Uninstall()
        {
            ExecuteScript(Resources.Uninstallation_sqlserver);

            return this;
        }

        /// <summary>
        ///   Executes an sql script.
        /// </summary>
        /// <param name = "sqlScript">The text of the sql script.</param>
        private void ExecuteScript(string sqlScript)
        {
            var dbAccess = new DbAccess(DbConnectionString);

            var regex = new Regex("go", RegexOptions.IgnoreCase | RegexOptions.Multiline);

            var lines = regex.Split(sqlScript);

            foreach (var commandStr in lines.Select(line => line.Trim()).Where(commandStr => commandStr.Length != 0))
            {
                var str = commandStr;

                dbAccess.ExecuteNonQuery(cmd => { cmd.CommandText = str; });
            }
        }
    }
}